#include "textureMaterial.h"

#include "shaderMaterial.h"

#include <iostream>
#include <fstream>
#include <GL/glew.h>

using namespace std;

ShaderMaterial::ShaderMaterial() : Material()  {

	textures = 0;vertex=0;fragment=0;program=0;
}

ShaderMaterial::ShaderMaterial(nv::vec4f diffuseAmbient, nv::vec4f specular,
		float shinyness) : Material(diffuseAmbient, specular, shinyness) {

	textures=0;vertex=0;fragment=0;program=0;
}

ShaderMaterial::~ShaderMaterial() {

	if (textures)
		delete textures;

	textures = 0;
}

string ShaderMaterial::LoadFromFile(string path) {

	// read from file, insert to string
	ifstream file(path.c_str(), ios::in | ios::ate);
	if (!file.is_open())
		return "";
	string data(file.tellg(), 0);
	file.seekg(ios::beg);
	file.read((char*) data.c_str(), (int) data.size());
	file.close();
	return data;
}

string ShaderMaterial::log(unsigned int obj) {

	int infologLength = 0;
	char infoLog[1024];

	if (glIsShader(obj))
		glGetShaderInfoLog(obj, 1024, &infologLength, infoLog);
	else
		glGetProgramInfoLog(obj, 1024, &infologLength, infoLog);

	return std::string(infoLog);
}

bool ShaderMaterial::loadShaders(string vertexShader, string fragmentShader) {


	string _vs = LoadFromFile(vertexShader);
	string _ps = LoadFromFile(fragmentShader);
	const char *vs = _vs.c_str();
	const char *ps = _ps.c_str();

	string logstr;

	// load shaders and compile program
	vertex = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex, 1, &vs, NULL);
	glCompileShader( vertex);
	logstr += log(vertex);

	fragment = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment, 1, &ps, NULL);
	glCompileShader( fragment);
	logstr += log(fragment);

	program = glCreateProgram();
	glAttachShader(program, vertex);
	glAttachShader(program, fragment);
	glLinkProgram( program);
	logstr += log(program);

	// print errors
	if (logstr.size())
		printf("Compiling program, VSPATH=%s, FSPATH=%s\n%s\n",
				vertexShader.c_str(), fragmentShader.c_str(), logstr.c_str());
	return logstr.size() == 0 ? true : false;
}

void ShaderMaterial::begin() {

	if(!program){
		printf("no shader program loaded");
		return;
	}

	setUpColors();
    glUseProgram(program);

	if(textures)
		textures->begin();

	textures->setUpShaderVariables(program);


}

void ShaderMaterial::end() {

	resetColors();
	glUseProgram(0);

	if(textures)
		textures->end();
}

void ShaderMaterial::setTextureMaterial(TextureMaterial *tex) {

	textures = tex;
}

int ShaderMaterial::getUniform(std::string name){

	if(program)
		return glGetUniformLocation(program, name.c_str());

	return -2;

}

